<template>
  <div class="watchFileX">

    <draggable-x :list="nowFileList" @end="changeFn"
                 :filter="canDraggFn"
                 :group-value="props.groupName" data-id="uid">
      <template #draggBox>
        <div class="watchItem" :class="props.itemClass"
             v-for="(file,index) in nowFileList" :key="`${file.uid}`"
             :id="`${file.uid}`">

          <!-- 文件内容 -->
          <div class="watchContent">
            <!-- 自定义内容 -->
            <slot v-if="slotNameFn(file)" :name="slotNameFn(file)" :file="file"/>

            <!-- 默认支持的图标 -->
            <div v-else class="fileBox" :class="props.fileClass">
              <div class="fileContent">
                <div class="fileType">
                  <!-- 图片类型 -->
                  <el-image class="item" v-if="isFile(file)==1" :src="file.url"
                            :preview-src-list="[file.url]" :initial-index="0" fit=""
                            preview-teleported lazy/>

                  <!-- 视频类型 -->
                  <video class="item video" v-else-if="isFile(file)==2" controls>
                    <source :src="file.url"/>
                    浏览器不支持该视频标签
                  </video>

                  <!-- 其他类型 -->
                  <div v-else class="otherBox item">
                    <slot name="other" :file="file">
                      <!-- <span class="otherName">{{ file.name }}</span>-->
                    </slot>
                  </div>
                </div>
              </div>

              <!-- 文件名称 -->
              <div class="fileNameBox">
                <slot name="fileName" :data="file">
                  <div class="fileName" v-if="props.showName">
                    <div class="nameBox">
                      <span>{{ file.name }}</span>
                    </div>
                  </div>
                </slot>
              </div>

            </div>

          </div>


          <!-- 遮蔽层 -->
          <div class="actionIcon el-upload-list__item-actions" v-if="props.overlay">
            <slot name="iconList" :data="file">
              <span class="iconBox">
                <!-- 预览 -->
                <slot name="lookIcon" :data="file">
                  <span v-show="!props.noLook" class="lookIcon icon"
                        @click="showImgFn(file)">
                    <icon-x type="zoomIn" size="26"/>
                  </span>
                </slot>

                <!-- 删除 -->
                <slot name="delIcon" :data="file">
                  <span v-show="!props.noDel" class="removeIcon icon"

                        @click="delFn(file,index)">
                    <icon-x type="Delete" size="26"/>
                  </span>
                </slot>
              </span>
            </slot>
          </div>

        </div>
      </template>

      <template #draggMore>
        <slot name="draggMore"/>
      </template>
    </draggable-x>

    <!-- 弹窗 -->
    <div class="dialogBox">
      <!-- 查看图片 -->
      <el-image-viewer v-if="showImg" :url-list="imgList" teleported
                       :initial-index="nowImgIndex"
                       @close="showImg = false" hide-on-click-modal/>

      <!-- 显示视频 -->
      <div v-if="showVideo">
        <dialog-x :title="'正在播放：'+videoInfo.name" :show="showVideo"
                  @close="showVideo = false" to-body
                  :showFooterBn="false">
          <video :src="videoInfo.url" style="width: 100%;height: 500px;" controls/>
        </dialog-x>
      </div>
    </div>
  </div>
</template>

<script setup>
import IconX from './xhykIcon.vue'
import DialogX from './xhykDialog.vue'
import DraggableX from "../xhyk/draggable/xhykDraggable.vue";
import { ElImageViewer,ElImage } from 'element-plus'
import {ref, computed, watch, onMounted} from 'vue'

const props = defineProps({
  // 根据元素自动判断
  // 路径列表：["https://element-plus.gitee.io/images/element-plus-logo.svg"]
  // 文件列表：[{name: '',url: '',raw: {type: 'image/png'},uid: ''}]
  list: {
    type: Object,
    default: []
  },

  // 拖拽分组名
  groupName: {
    type: String,
    default: "watchDraggX"
  },

  // 禁止拖拽
  disabled: {
    type: Boolean,
    default: false
  },

  // 拖拽改变的方式
  changeType: {
    type: [String, Number],
    default: 0
  },

  // 回调函数：自定义插槽名称
  slotNameFn: {
    type: Function,
    // 返回非空字符串时，使用自定义插槽，该字符串为插槽名称
    default: file => {
      return undefined
    }
  },
  // itemClass
  itemClass: {
    type: [String, Object],
    default: "itemClass"
  },
  // 文件类名
  fileClass: {
    type: [String, Object],
    default: "fileClass"
  },

  // 是否显示遮蔽层
  overlay: {
    type: Boolean,
    default: true
  },

  // 总是显示遮蔽层
  alwaysOverlay: {
    type: Boolean,
    default: false
  },


  // del图标
  noDel: {
    type: Boolean,
    default: false
  },

  // 查看图标
  noLook: {
    type: Boolean,
    default: false
  },

  // 是否查看全部图片
  allImg: {
    type: [Boolean, String, Number],
    default: true
  },

  // 返回false时，不使用默认显示方式
  showBefore: {
    type: Function,
    default: undefined
  },

  // 是否显示名称
  showName: {
    type: Boolean,
    default: true
  },

  // 是否自定义删除函数
  delFn: {
    type: Function,
    default: undefined
  },

  // 图框宽
  width: {
    type: [String, Number],
    default: '146'
  },

  // 图框高
  height: {
    type: [String, Number],
    default: '146'
  },

})

const emit = defineEmits(['show', 'update:list', 'change', 'del'])

function getStrRightR(str, strBefore, False = undefined, toLower = false) {
  const oldStr = str
  if (toLower) {
    str = str.toLowerCase()
    strBefore = strBefore.toLowerCase()
  }
  try {
    let before = str.lastIndexOf(strBefore);
    if (before == -1) {
      return False == undefined ? undefined : False
    }
    return oldStr.slice(before + strBefore.length)
  } catch (err) {
    return False == undefined ? undefined : False
  }
}

// 判断文件类型
class MyFile {
  static imgList = ["jpg", "jpeg", "png", "gif", "bmp", "tiff", "icon", "svg", "webp"]
  static videoList = ["mp4", "avi", "mov", "wmv", "flv", "mkv", "rmvb", "webm", "ogv", "3gp"]
  static mp3List = ["wav", "mp3", "aif", "aiff", "mid", "cdda", "wma"]
  static pdfList = ["pdf"]


  constructor(file) {
    this.file = file.replaceAll("\\", '/')
  }

  getInfo() {
    const result = {
      url: this.file,
      name: '',
      raw: {
        name: '',
        type: ''
      }
    }

    let name = getStrRightR(this.file, '/', "")
    result.raw.name = name;
    result.name = name;
    let nameType = getStrRightR(this.file, '.', this.file)
    nameType = nameType.toLowerCase()
    if (MyFile.imgList.includes(nameType)) {
      result.raw.type = `image/${nameType}`
    } else if (MyFile.videoList.includes(nameType)) {
      result.raw.type = `video/${nameType}`
    } else if (MyFile.pdfList.includes(nameType)) {
      result.raw.type = `application/pdf`
    } else {
      result.raw.type = `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`
    }
    return result
  }
}

// 判断文件类型
const isFile = file => {
  // 如果是自定义插槽则不显示
  if (props.slotNameFn(file)) {
    return 0
  }
  // 如果是超过limit的文件，file是raw对象
  const type = file?.raw?.type || ''
  if (type.indexOf('image') != -1) {
    return 1
  } else if (type.indexOf('video') != -1) {
    return 2
  }
  return 0
}


// 宽高
const widthD = computed(() => {
  let result = props.width
  if (typeof result == 'string') {
    result = result.toLowerCase()
    if (!result.includes('px') && !result.includes('%') &&
        !result.includes('vh') && !result.includes('auto') &&
        !result.includes('vw')) {
      result = `${result}px`
    }
  } else {
    result = `${result}px`
  }
  return result
})

const heightD = computed(() => {
  let result = props.height
  if (typeof result == 'string') {
    result = result.toLowerCase()
    if (!result.includes('px') && !result.includes('%') &&
        !result.includes('vh') && !result.includes('auto') &&
        !result.includes('vw')) {
      result = `${result}px`
    }
  } else {
    result = `${result}px`
  }
  return result
})

// 是否可以拖拽
const canDraggFn = (item) => {
  return props.disabled
}

// 当前文件列表
const nowFileList = ref([])
watch(() => props.list, (newV) => {
  nowFileList.value = []
  newV?.forEach(row => {
    if (typeof row == 'object') {
      if (row.uid == undefined) {
        if (!row.name) {
          let tempObj = new MyFile(row.url || "")
          let info = tempObj.getInfo()
          row.name = info.name
        }
        row.uid = `${Date.now()}_${row.name}`
      }
      nowFileList.value.push(row)
    } else {
      // 直接是路径的列表
      let newFile = new MyFile(row)
      let info = newFile.getInfo()
      info.uid = `${Date.now()}_${info.name}`
      nowFileList.value.push(info)
    }
  })
}, {immediate: true, deep: true})


/* 动画类名 */
const AnimationClass = ref(['el-list-leave-active', 'el-list-move', 'el-list-leave-to'])

// 删除方法
const delFn = async (file, index) => {
  let tempId = `${file.uid}`
  if (props.delFn) {
    await props.delFn(row, index, tempId)
  } else {
    let tempObj = nowFileList.value[index]
    if (tempObj.uid == file.uid) {
      // 设置动画
      let tempDom = document.getElementById(`${tempId}`)
      if (tempDom) {
        tempDom.classList.add(...AnimationClass.value)
      }
      // 是同一个了
      setTimeout(() => {
        // 修复过快时索引不对
        let thisIndex = 0
        nowFileList.value.find((item, index) => {
          if (item.uid == file.uid) {
            thisIndex = index;
            return true
          }
        })

        nowFileList.value.splice(thisIndex, 1)
        let tempUrlList = []
        nowFileList.value.forEach(row => {
          // 判断是路径还是文件
          let isUrl = true
          if (props.list.length > 0) {
            if (typeof props.list[0] == 'object') {
              isUrl = false
            }
          }
          if (isUrl) {
            tempUrlList.push(row.url)
          } else {
            tempUrlList.push(row)
          }
        })
        emit("del", {
          item: file,
        })
        emit("change", tempUrlList)
        emit("update:list", tempUrlList)
      }, 500)
    }
  }
}


// 显示
const showFile = async (file, showAll) => {
  const fileType = isFile(file)
  emit('show', {file, type: fileType})
  if (typeof props.showBefore == 'function') {
    let keep = await props.showBefore(file)
    if (!keep) {
      return;
    }
  }
  switch (fileType) {
      // 显示图片
    case 1:
      imgList.value = []
      nowFileList.value.find((row, index) => {
        let isAll = true
        if (props.allImg == false || props.allImg == '0' || props.allImg == 0) {
          isAll = false
        }
        if (isAll) {
          // 显示全部图片
          imgList.value.push(row.url)
          if (row.url == file.url) {
            nowImgIndex.value = index
          }
        } else {
          // 只显示一张
          imgList.value.push(file.url)
          nowImgIndex.value = 0
          return true
        }
      })
      showImg.value = true
      break
    case 2:
      videoInfo.value = {
        name: file.name,
        url: file.url
      }
      showVideo.value = true
      break
    default:
      // 判断是否为pdf
      let fileObj = new MyFile(file.url).getInfo()
      // 获取后缀名
      if (fileObj.raw.type.includes('pdf')) {
        window.open(file.url, '_blank', 'toolbar=no,scrollbars=no,resizable=no,status=no')
      }
  }
}

// 显示图片
const showImg = ref(false)
const imgList = ref([])
// 当前位置
const nowImgIndex = ref(0)
const showImgFn = (file, index) => {
  showFile(file, props.allImg)
}


// 显示视频
const showVideo = ref(false)
const videoInfo = ref({})


// 我的列表
class MyList {
  constructor(list = []) {
    this.list = list
  }


  // 列表添加数据。
  add(newIndex = 1, newObj = {}, changeType = 0) {
    let long = this.list.length - 0
    if (newIndex > long) {
      newIndex = long
    }
    switch (changeType) {
        // 插入新位置
      case 0:
        this.list.splice(newIndex, 0, newObj)
        break;
        // 替换
      case 1:
        this.list[newIndex] = newObj
        break;
    }
    return this.list;
  }

  // 将原来的数据进行改变位置。
  // oldIndex：被改变位置的数据索引
  // newIndex：放到新位置
  changeIndex(oldIndex, newIndex, changeType = 0) {
    let long = this.list.length - 1
    // 溢出时不操作
    if (newIndex > long || oldIndex > long) {
      return;
    }
    let newObj = this.list[newIndex]
    let oldObj = this.list[oldIndex]

    switch (changeType) {
      case 0:
        // 0：新位置比旧位置大时，旧数据往左边移。新位置比旧位置小时，旧数据往右边移
        // 如果是改变的第一个位置
        if (newIndex == 0) {
          this.list.splice(oldIndex, 1)
          this.list.unshift(oldObj)
        }
        // 最后一个位置
        else if (newIndex == long) {
          this.list.splice(oldIndex, 1)
          this.list.push(oldObj)
        } else {
          // 其他位置。先分前后段
          let before = this.list.slice(0, oldIndex)
          let after = this.list.slice(oldIndex + 1, long + 1)
          if (newIndex < oldIndex) {
            // 数据应该插入在前段
            before.splice(newIndex, 0, oldObj)
          } else {
            // 数据插入在后段
            after.splice(newIndex - oldIndex, 0, oldObj)
          }
          let newList = [...before, ...after]
          newList.forEach((row, index) => {
            this.list[index] = row
          })
        }

        break;

      case 1:
        // 两个位置换行
        this.list[oldIndex] = newObj
        this.list[newIndex] = oldObj
        break;
      case 2:


        break
    }


    return this.list;
  }

}


// 拖拽
const changeFn = async (options) => {
  // 排序位置
  let newIndex = options?.event?.newIndex || 0
  let oldIndex = options?.event?.oldIndex || 0
  // console.log(newIndex,oldIndex)
  // 改变位置
  let tempUrlList = []
  nowFileList.value.forEach(row => {
    // 判断是路径还是文件
    let isUrl = true
    if (props.list.length > 0) {
      if (typeof props.list[0] == 'object') {
        isUrl = false
      }
    }
    if (isUrl) {
      tempUrlList.push(row.url)
    } else {
      tempUrlList.push(row)
    }
  })

  let tempObj = new MyList(tempUrlList)

  await tempObj.changeIndex(oldIndex, newIndex, parseInt(props.changeType));

  emit("change", tempUrlList)
  emit("update:list", tempUrlList)
}


// 总是显示遮蔽层
const overlayZindex = computed(() => {
  return props.alwaysOverlay ? 4 : 2
})
const overLayDisPlay = computed(() => {
  return props.alwaysOverlay ? 'flex' : 'none'
})


defineExpose({
  showFile
})
</script>

<style scoped lang='scss'>
.watchFileX {
  width: auto;
  height: auto;

  .watchItem {
    width: 100%;
    height: 100%;
    transition: all 0.5s cubic-bezier(.55, 0, .1, 1);
    vertical-align: top;
  }
}

// 默认的item类名
:deep(.itemClass) {
  width: v-bind(widthD) !important;
  height: v-bind(heightD) !important;
  position: relative;
  display: inline-block;
  margin: 6px 6px;
  overflow: hidden;
  border-radius: 6px;
  border: 1px solid #DCDFE6;

  .watchContent {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
  }

  .actionIcon {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
  }
}


// 内容
:deep(.watchContent) {
  .fileBox {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;

    // 文件内容
    .fileContent {
      flex: 1 1 auto;
      position: relative;

      .fileType {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;

        .item {
          width: 100%;
          height: 100%;

          .el-image__inner {
            width: v-bind(widthD);
            height: v-bind(heightD);
          }

          .otherName {
            word-break: break-all;
            display: flex;
          }
        }
      }


    }

    // 名称
    .fileNameBox {
      flex: 0 0 auto;
      padding: 0px 6px;
      border-top: 1px solid #dddddd;
      position: relative;

      .nameBox {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        text-align: center;
      }
    }
  }
}

// 鼠标进入改变遮蔽层
.watchItem {

  .watchContent {
    z-index: 3;
  }

  .actionIcon {
    z-index: v-bind(overlayZindex);
    display: v-bind(overLayDisPlay);
  }

  // 鼠标进入时遮蔽层在上
  &:hover {
    .watchContent {
      z-index: 2 !important;
    }

    .actionIcon {
      z-index: 3 !important;
      display: flex !important;
    }
  }
}

.actionIcon {
  background-color: rgba(0, 0, 0, .5);
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
}

// 图标
.iconBox {
  display: flex;
}

.icon {
  color: white;
  cursor: pointer;
}

.lookIcon {
  margin-right: 6px;
  display: flex;
}

.removeIcon {
  display: flex;
  margin-left: 6px;
}

// 其他类型名称
.otherName {
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

</style>